﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Modules.Contracts.DTO;
using System.Modules.Extensions;
using System.Modules.SharePoint.Contracts.DTO;
using System.Reflection;
using System.Windows.Forms;

namespace Ahmad.A.Ousman.DotNetExtensions.Demonstration
{
    public partial class MainForm : Form
    {
        #region Constructor
        public MainForm()
        {
            InitializeComponent();
            LoadForm();
        }
        #endregion

        #region Methods
        void LoadForm()
        {
            BindConstants();
            BindDTOs();
            BindExceptionHandling();
            BindLogging();
        }

        void BindDTOs()
        {
            var dtos = (from type in Assembly.GetTypes() where type.Namespace.IsNotNullOrEmpty() && type.Namespace.StartsWith(NAMESPACE_DTO) && type.IsClass select type).ToList();
            var rootNode = new TreeNode { Text = NAMESPACE_DTO };
            foreach (var constant in dtos)
            {
                var node = new TreeNode { Text = constant.Name };
                var fields = constant.GetFields(BindingFlags.Public | BindingFlags.Static);
                if (fields.Length > 0)
                {
                    var fieldsNode = new TreeNode { Text = "Fields" };
                    foreach (var fieldNode in fields.Select(fieldInfo => new TreeNode { Text = string.Format("{0} = \"{1}\"", fieldInfo.Name, fieldInfo.GetRawConstantValue()) }))
                    {
                        fieldsNode.Nodes.Add(fieldNode);
                    }
                    node.Nodes.Add(fieldsNode);
                }
                var properties = constant.GetProperties();
                if (properties.Length > 0)
                {
                    var propertiesNode = new TreeNode { Text = "Properties" };
                    foreach (var propertyNode in properties.Select(propertyInfo => new TreeNode { Text = propertyInfo.Name }))
                    {
                        propertiesNode.Nodes.Add(propertyNode);
                    }
                    node.Nodes.Add(propertiesNode);
                }
                var methods = constant.GetMethods();
                if (methods.Length > 0)
                {
                    var methodsNode = new TreeNode { Text = "Methods" };
                    foreach (var methodNode in methods.Where(methodInfo => !methodInfo.Name.StartsWith("get_") && !methodInfo.Name.StartsWith("set_")).ToList().Select(methodInfo => new TreeNode { Text = methodInfo.Name }))
                    {
                        methodsNode.Nodes.Add(methodNode);
                    }
                    node.Nodes.Add(methodsNode);
                }
                rootNode.Nodes.Add(node);
            }
            treeViewDTO.Nodes.Add(rootNode);
            treeViewDTO.ExpandAll();
        }

        void BindConstants()
        {
            var constants = (from type in Assembly.GetTypes() where type.Namespace.IsNotNullOrEmpty() && type.Namespace.StartsWith(NAMESPACE_CONSTANTS) && type.IsClass select type).ToList();
            var rootNode = new TreeNode { Text = NAMESPACE_CONSTANTS };
            foreach (var constant in constants)
            {
                var node = new TreeNode { Text = constant.Name };
                var fields = constant.GetFields(BindingFlags.Public | BindingFlags.Static);
                foreach (var fieldNode in fields.Select(fieldInfo => new TreeNode { Text = string.Format("{0} = \"{1}\"", fieldInfo.Name, fieldInfo.GetRawConstantValue()) }))
                {
                    node.Nodes.Add(fieldNode);
                }
                rootNode.Nodes.Add(node);
            }
            treeViewConstants.Nodes.Add(rootNode);
            treeViewConstants.ExpandAll();
        }

        void BindExceptionHandling()
        {
            var exceptionHandling = (from type in Assembly.GetTypes() where type.Namespace.IsNotNullOrEmpty() && type.Namespace.StartsWith(NAMESPACE_EXCEPTION_HANLDING) && type.IsClass select type).ToList();
            var rootNode = new TreeNode { Text = NAMESPACE_EXCEPTION_HANLDING };
            foreach (var type in exceptionHandling)
            {
                var node = new TreeNode { Text = type.Name };
                var methods = type.GetMethods();
                if (methods.Length > 0)
                {
                    var methodsNode = new TreeNode { Text = "Methods" };
                    foreach (var methodInfo in methods.Where(methodInfo => !methodInfo.Name.StartsWith("get_") && !methodInfo.Name.StartsWith("set_")).ToList())
                    {
                        var methodNode = new TreeNode { Text = methodInfo.ToString(), Tag = methodInfo };
                        methodsNode.Nodes.Add(methodNode);
                    }
                    node.Nodes.Add(methodsNode);
                }
                rootNode.Nodes.Add(node);
            }
            treeViewExceptionHandling.Nodes.Add(rootNode);
            treeViewExceptionHandling.ExpandAll();
        }

        void BindLogging()
        {
            var rootNode = new TreeNode { Text = NAMESPACE_LOGGING };
            var nameSpaces = (from type in Assembly.GetTypes() where type.Namespace.IsNotNullOrEmpty() && type.Namespace.StartsWith(NAMESPACE_LOGGING) && type.IsClass select type.Namespace).Distinct();
            foreach (var nameSpace in nameSpaces)
            {
                var nodeNameSpace = new TreeNode { Text = nameSpace };
                var logging = (from type in Assembly.GetTypes() where type.Namespace.IsNotNullOrEmpty() && type.Namespace.StartsWith(nameSpace) && type.IsClass select type).ToList();
                foreach (var type in logging)
                {
                    var node = new TreeNode { Text = type.Name };
                    var methods = type.GetMethods();
                    if (methods.Length > 0)
                    {
                        var methodsNode = new TreeNode { Text = "Methods" };
                        foreach (var methodInfo in methods.Where(methodInfo => !methodInfo.Name.StartsWith("get_") && !methodInfo.Name.StartsWith("set_")).ToList())
                        {
                            var methodNode = new TreeNode { Text = methodInfo.ToString(), Tag = methodInfo };
                            methodsNode.Nodes.Add(methodNode);
                        }
                        node.Nodes.Add(methodsNode);
                    }
                    nodeNameSpace.Nodes.Add(node);
                }
                rootNode.Nodes.Add(nodeNameSpace);
            }
            treeViewLogging.Nodes.Add(rootNode);
            treeViewLogging.ExpandAll();
        }
        #endregion

        #region Constants
        private const string ASSEMBLY_FULL_NAME = "System.Modules, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c9bb6b0d2e20a1e5";
        private const string NAMESPACE_CONSTANTS = "System.Modules.Constants";
        private const string NAMESPACE_DTO = "System.Modules.DTO";
        private const string NAMESPACE_EXCEPTION_HANLDING = "System.Modules.ExceptionHanlding";
        private const string NAMESPACE_LOGGING = "System.Modules.Logging";
        #endregion

        #region Properties
        private Assembly _assembly;
        private Assembly Assembly
        {
            get { return _assembly ?? (_assembly = Assembly.Load(ASSEMBLY_FULL_NAME)); }
        }
        #endregion

        #region Event Handlers
        public class MyClass : Initiator
        {
            public int I { get; set; }
            public bool B { get; set; }
            public string S { get; set; }
            public DateTime DateTime { get; set; }
            public SPListFolder folder { get; set; }
            public TaskListItem TaskListItem { get; set; }
            public Dictionary<string, object> Dictionary { get; set; }
        }
        private void ToolStripButtonTryClick(object sender, EventArgs e)
        {
            var module = new MyClass();
        }
        #endregion
    }
}
